﻿using System;
using System.Collections.Generic;
using System.Linq;
using Xenta.Entities;
using Xenta.Utils;

namespace Xenta.Operations
{
    #region __General__

    /// <summary>
    /// Represents the generic attribute create operation.
    /// </summary>
    /// <typeparam name="TAttr">The type of attribute.</typeparam>
    public class CreateGenericAttribute<TAttr> : CreateAuditable<TAttr>
        where TAttr : GenericAttributeEntity
    {
        #region Properties

        /// <summary>
        /// Gets or sets the holder identifier.
        /// </summary>
        public int HolderID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the key.
        /// </summary>
        public string Key
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        public string Value
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(String.IsNullOrWhiteSpace(Key))
                return Err.Of<TAttr>().NotValid("Key");
            return base.Validate(uow);
        }

        protected override void Construct(IUnitOfWork uow, TAttr entity)
        {
            base.Construct(uow, entity);

            entity.HolderID = HolderID;
            entity.Key = Key.TrimToLen(100);
            entity.Value = StringHelper.EnsureNotNull(Value).TrimToLen(4000);
        }

        #endregion
    }

    /// <summary>
    /// Represents the generic attribute update operation.
    /// </summary>
    /// <typeparam name="TAttr">The type of attribute.</typeparam>
    public class UpdateGenericAttribute<TAttr> : UpdateAuditable<TAttr>
        where TAttr : GenericAttributeEntity
    {
        #region Properties

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        public string Value
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Revise(IUnitOfWork uow, TAttr entity)
        {
            base.Revise(uow, entity);

            entity.Value = StringHelper.EnsureNotNull(Value).TrimToLen(4000);
        }

        #endregion
    }

    /// <summary>
    /// Represents the generic attribute set operation base.
    /// </summary>
    /// <typeparam name="TAttr">The type of attribute.</typeparam>
    public class SetGenericAttribute<TAttr> : Operation<TAttr>
        where TAttr : GenericAttributeEntity
    {
        #region Properties

        /// <summary>
        /// Gets or sets the holder identifier.
        /// </summary>
        public int HolderID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the key.
        /// </summary>
        public string Key
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        public string Value
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out TAttr result)
        {
            var entity = uow.Execute(new GetGenericAttributeByKey<TAttr>
            {
                HolderID = HolderID,
                Key = Key
            }).Result;

            if(entity == null)
            {
                entity = uow.Execute(new CreateGenericAttribute<TAttr>
                {
                    HolderID = HolderID,
                    Key = Key,
                    Value = Value
                }).Result;
            }
            else
            {
                entity = uow.Execute(new UpdateGenericAttribute<TAttr>
                {
                    EntityID = entity.EntityID,
                    Value = Value
                }).Result;
            }

            result = entity;
        }

        #endregion
    }

    /// <summary>
    /// Deletes the generic attribute.
    /// </summary>
    /// <typeparam name="TAttr">The type of attribute.</typeparam>
    public class DeleteGenericAttribute<TAttr> : DeleteEntity<TAttr>
        where TAttr : GenericAttributeEntity
    {
    }

    /// <summary>
    /// Gets the generic attribute by identifier.
    /// </summary>
    /// <typeparam name="TAttr">The type of attribute.</typeparam>
    public class GetGenericAttribute<TAttr> : GetEntity<TAttr>
        where TAttr : GenericAttributeEntity
    {
    }

    /// <summary>
    /// Gets the generic attribute by the key.
    /// </summary>
    /// <typeparam name="TAttr">The type of attribute.</typeparam>
    public class GetGenericAttributeByKey<TAttr> : QueryEntity<TAttr>
        where TAttr : GenericAttributeEntity
    {
        #region Properties

        /// <summary>
        /// Gets or sets the holder identifier.
        /// </summary>
        public int HolderID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the key.
        /// </summary>
        public string Key
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override IQueryable<TAttr> Build(IUnitOfWork uow, IQueryable<TAttr> query)
        {
            string key = StringHelper.EnsureNotNull(Key).TrimToLen(100);
            query = base.Build(uow, query).Where(x => 
                x.HolderID == HolderID && 
                x.Key.Equals(key));
            return query;
        }

        #endregion
    }

    /// <summary>
    /// Gets the generic attribute value by key.
    /// </summary>
    /// <typeparam name="TAttr">The type of attribute.</typeparam>
    public class GetGenericAttributeValueByKey<TAttr> : Operation<String>
        where TAttr : GenericAttributeEntity
    {
        #region Properties

        /// <summary>
        /// Gets or sets the holder identifier.
        /// </summary>
        public int HolderID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the setting key.
        /// </summary>
        public string Key
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out string result)
        {
            result = String.Empty;
            var entity = uow.Execute(new GetGenericAttributeByKey<TAttr>
            {
                HolderID = HolderID,
                Key = Key
            }).Result;
            if(entity == null) 
                return;
            result = entity.Value;
        }

        /// <summary>
        /// Gets the result converted into type T.
        /// </summary>
        /// <typeparam name="T">The target type to convert.</typeparam>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>The result as type T.</returns>
        public T ResultAs<T>(T defaultValue = default(T))
        {
            return Result.ParseAs(defaultValue);
        }

        #endregion
    }

    #endregion

    #region __Bulk__

    /// <summary>
    /// Updates the generic attributes from dictionary.
    /// </summary>
    public class BulkUpdateGenericAttributes<TAttr> : Operation
        where TAttr : GenericAttributeEntity
    {
        #region Properties

        /// <summary>
        /// Gets or sets the account identifier.
        /// </summary>
        public int HolderID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the attribute dictionary.
        /// </summary>
        public IDictionary<String, String> Attributes
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(Attributes == null || !Attributes.Any())
                Err.Of(this).No("Attributes");
            return base.Validate(uow);
        }

        protected override void Work(IUnitOfWork uow)
        {
            foreach(var i in Attributes)
            {
                uow.Execute(new SetGenericAttribute<TAttr>
                {
                    HolderID = HolderID,
                    Key = i.Key,
                    Value = i.Value
                });
            }
        }

        #endregion
    }

    #endregion
}
